﻿using System;
using System.Collections.Generic;
using System.Text;
using SpellChecker;
using System.Text.RegularExpressions;
using System.Linq;

namespace SpellChecker
{
    public class SpCheckerModel
    {
        private List<StringRow> dictionary;  // Dictionary of correct words
        private List<String> userInputList; // Words of the user input (potentially misspelt)
        private SpellCheckerEngine spellCheckEngine;
        private Dictionary<String, String> engToArm;
        private char[] SPLIT = new char[] {' ','~','`','!','#','$','%','^','&','*','(',')','_','-','+','=','|','\\',',','<','>','.',
                                       '/','?','՝','~','{','}','[',']','«','»','՞','"','\''};
        public SpCheckerModel()
        {
            engToArm = new Dictionary<String, String>();
            dictionary = new List<StringRow>();
            userInputList = new List<string>();
            spellCheckEngine = new SpellCheckerEngine(wordLengthRestriction, 2); // 2 means 2 edits!!!
                                                                       // increasing edits will result perfomance issues         
        }


        public List<StringRow> find(String searchText)
        {
            List<StringRow> sortedList = new List<StringRow>();
            if (searchText == null)
                return sortedList;
            LanguageCode lang = spellCheckEngine.detectLanguage(searchText);
            String[] searchWords = searchText.Split(SPLIT);
            Dictionary<String, StringRow[]> wordToSuggestions = new Dictionary<String, StringRow[]>();
            // Filling suggestions for all search words
            switch (lang)
            {
                case LanguageCode.Armenian:
                    foreach (var searchWord in searchWords)
                    {
                        if (wordToSuggestions.ContainsKey(searchWord))
                            continue;
                        wordToSuggestions.Add(searchWord, spellCheckEngine.searchFor(searchWord, dictionary, LanguageCode.Armenian));
                    }
                    break;
                case LanguageCode.Russian:
                    foreach (var searchWord in searchWords)
                    {
                        if (wordToSuggestions.ContainsKey(searchWord))
                            continue;

                        wordToSuggestions.Add(searchWord, spellCheckEngine.searchFor(searchWord, dictionary, LanguageCode.Russian));
                    }
                    break;
                case LanguageCode.English:
                    // Should be added eng to rus converter and search in russian progs
                    foreach (var searchWord in searchWords)
                    {

                        if (searchWord.Equals("") || wordToSuggestions.ContainsKey(searchWord))
                            continue;
                        String[] armWords = spellCheckEngine.getEngToArm(searchWord);
                        String[] rusWords = spellCheckEngine.getEngToRus(searchWord);
                        StringRow[] engResult = spellCheckEngine.searchFor(searchWord, dictionary, LanguageCode.English);
                        StringRow[] armResult = spellCheckEngine.searchFor(armWords, dictionary, LanguageCode.Armenian);
                        StringRow[] rusResult = spellCheckEngine.searchFor(rusWords, dictionary, LanguageCode.Russian);
                        StringRow[] allResult = new StringRow[engResult.Length + armResult.Length + rusResult.Length];

                        engResult.CopyTo(allResult, 0);
                        armResult.CopyTo(allResult, engResult.Length);
                        rusResult.CopyTo(allResult, armResult.Length + engResult.Length);
                        wordToSuggestions.Add(searchWord, allResult);
                        //wordToSuggestions.Add(searchWord, spellCheckEngine.searchFor(rusWords, dictionary, LanguageCode.Russian));
                    }
                    break;
                case LanguageCode.None: return new List<StringRow>();
            }

            

            foreach (var rows in wordToSuggestions.Values)
            {
                foreach (var row in rows)
                {
                    if (!sortedList.Contains(row))
                        sortedList.Add(row);
                }
            }

            sortedList = sortedList.GroupBy(o => o.Value).Select(o => o.First()).ToList();

            sortedList = sortedList.OrderByDescending(o=> o.Priority).ToList();
            // Removing the priorities to not affect on next searches
            foreach (var item in sortedList)
                item.Priority = 0;

            sortedList = sortedList.Distinct().ToList();

            return sortedList;
        }

        private string getArmenianProgs(String[] armWords)
        {
            StringBuilder sb = new StringBuilder();
            //foreach (String st in armWords)
           // {
                foreach (var strRow in spellCheckEngine.searchFor(armWords, dictionary, LanguageCode.Armenian))
                {
                    sb.Append(strRow);
                    sb.Append('\n');
                }
            //}
            return sb.ToString();
        }



        /// <summary>
        /// Returns whether the word1 word2 combination correspond restrictions or not
        /// </summary>
        /// <param name="word1">
        /// Misspelt word
        /// </param>
        /// <param name="word2">
        /// Suggestion for word1
        /// </param>
        private bool restriction(string word1, string word2)
        {
            if (word1 == null || word2 == null)
                return false;
            if (System.Math.Abs(word1.Length - word2.Length) < 2)
                return true;
            string bigger = word1.Length > word2.Length ? word1 : word2;
            string smaller = bigger.Equals(word1) ? word2 : word1;
            for (int i = 0; i < bigger.Length - 1; i++)
            {
                string s = bigger.Substring(0, i) + bigger.Substring(i + 2);
                if (smaller.Equals(s))
                    return true;
            }
            return false;
        }

        private bool wordLengthRestriction(String word1, String word2)
        {
            if (word1 == null || word2 == null)
                return false;
            double k = (double)System.Math.Abs(word1.Length - word2.Length) / System.Math.Max(word1.Length, word2.Length);
            if (k > 0.4)
                return false;
            else
                return true;
        }

        /// <summary>
        /// Fills dictionaries with correct dictionary data and user input misspelt data
        /// </summary>
        public void initSearchEngine(List<String> inputData)
        {
            foreach (String item in inputData)
            {
                if (item.Equals(""))
                    continue;                
                dictionary.Add(new StringRow(item)); 
            }
        }
    }
}
